package com.fz.song.provider;

import com.fz.song.exception.VerificationCodeException;
import com.fz.song.service.MyUserDetailsService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;


/**
 *
 * AuthenticationProvider是一个验证过程的接口,
 * 他有一个抽象类AbstractUserDetailsAuthenticationProvider,其中实现了验证方法,但是retrieveUser(检索用户)
 * 和additionalAuthenticationChecks(附加认证过程)这两个抽象方法没有实现,但是DaoAuthenticationProvider这个继承了AbstractUserDetailsAuthenticationProvider
 * 实现了这两个方法.我们需要自己写一个类重写additionalAuthenticationChecks方法,在这里校验验证码就可以了,但是又出现一个问题,验证码保存在请求中和session中,这里没有怎么办呢?
 * UsernamePasswordAuthenticationToken是Authentication的实现类,在Authentication中有一个getDetails方法,可以用作传递这个值,但是getDetails在哪里设置呢?
 * UsernamePasswordAuthenticationFilter的attemptAuthentication方法中调用了setDetails,传递了一个request,
 *
 *
 * 这是一个验证过程,
 * 自定义的验证过程
 */
@Component
public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    public MyAuthenticationProvider(MyUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.setUserDetailsService(userDetailsService);
        this.setPasswordEncoder(passwordEncoder);
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        //实现图形验证码校验逻辑
        MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
        if (!details.isImageCodeIsRight()) {
            throw new VerificationCodeException();
        }
        //调用父类方法完成密码校验
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}
